package com.mezz.bones.im.sdk.client;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mezz.bones.im.sdk.domain.base.BaseRequest;
import com.mezz.bones.im.sdk.domain.base.BaseResponse;
import com.mezz.bones.im.sdk.exception.LaicuiImException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;

/**
 * @author metz
 * @date 2022-09-13 09:32
 * @description:
 */
@Slf4j
@Data
public class LaicuiImClient {

    private String appId;
    private String appSecret;
    private String gateway;

    public LaicuiImClient(String gateway, String appId, String appSecret) {
        this.gateway = gateway;
        this.appId = appId;
        this.appSecret = appSecret;
    }


    public <R> BaseResponse<R> execute(BaseRequest<R> request) {

        BaseResponse baseResponse = null;
        String body = "";
        LaicuiImRequestHeader header = new LaicuiImRequestHeader();

        try {
            HttpResponse httpResponse;
            header.setAppId(this.appId);
            header.setUrl(request.getUrl());
            header.setNonce(RandomUtil.randomString(15));
            header.setTimestamp(new Date().getTime() + "");
            body = JSONObject.toJSONString(request);
            String sign = generateSign(header.getAppId(), request.getUrl(), header.getNonce(), header.getTimestamp());
            header.setSign(sign);

            // 优化请求开始日志
            log.info("IM请求开始 | URL:{} | 方法:{}", 
                    StrUtil.concat(true, this.gateway, request.getUrl()),
                    request.getClass().getSimpleName());
            
            // 添加debug级别的请求参数日志
            log.debug("IM请求参数 | Header:{} | Body:{}", 
                    JSONObject.toJSONString(header), 
                    body);

            Date reqStartTime = new Date();
            HttpRequest httpRequest = HttpRequest.post(StrUtil.concat(true, this.gateway, request.getUrl()))
                    .header("Content-Type", "application/json; charset=utf-8")
                    .header("appId",this.appId)
                    .header("nonce",header.getNonce())
                    .header("timestamp",header.getTimestamp())
                    .header("sign",sign)
                    .setConnectionTimeout(5000)
                    .body(body);

            httpResponse = httpRequest.execute();

            String responseBody = httpResponse.body();
            
            // 优化响应日志，添加debug级别的响应内容
            log.info("IM请求结束 | URL:{} | 状态码:{} | 耗时:{}ms",
                    StrUtil.concat(true, this.gateway, request.getUrl()),
                    httpResponse.getStatus(),
                    System.currentTimeMillis() - reqStartTime.getTime());
                    
            log.debug("IM响应内容 | Body:{}", responseBody);

            baseResponse = JSONObject.parseObject(responseBody, BaseResponse.class);
            Object data = baseResponse.getData();

            if (data == null) {
                return baseResponse;
            }

            if (data instanceof JSONArray) {
                log.error("响应数据格式错误：数据必须是对象格式，当前类型为 {}", data.getClass().getSimpleName());
                throw new RuntimeException("请联系开发者修改");
            }

            if (!(data instanceof JSONObject)) {
                log.error("响应数据格式错误：数据必须是对象格式，当前类型为 {}", data.getClass().getSimpleName());
                throw new RuntimeException("请联系开发者修改");
            }

            //获取真实泛型类型
            ParameterizedType parameterizedType = (ParameterizedType) request.getClass().getGenericSuperclass();
            Type actualTypeArgument = parameterizedType.getActualTypeArguments()[0];

            R r = (R) BeanUtil.toBean(baseResponse.getData(), ((Class) actualTypeArgument));
            baseResponse.setData(r);

        } catch (Exception e) {
            // 优化错误日志格式
            log.error("IM请求异常 | URL:{} | 方法:{} | 错误类型:{} | 错误信息:{} | 请求头:{} | 请求体:{}", 
                    StrUtil.concat(true, this.gateway, request.getUrl()),
                    request.getClass().getSimpleName(),
                    e.getClass().getSimpleName(),
                    e.getMessage(),
                    JSONObject.toJSONString(header),
                    body,
                    e);
            throw new LaicuiImException(StrUtil.format("IM请求错误 - [{}] {}", 
                    e.getClass().getSimpleName(),
                    e.getMessage()));
        }

        return baseResponse;
    }

    public String generateSign(String appId, String url, String nonce, String timestamp) {
        String plaintext = StrUtil.concat(true, this.appSecret,
                appId,
                url,
                nonce,
                timestamp,
                this.appSecret
        );
        String sign = SecureUtil.sha256(plaintext);
        // 添加debug级别的签名日志
        log.debug("IM签名生成 | 明文:{} | 签名:{}", plaintext, sign);
        return sign;
    }

}
